function ResponseLayer(width, height, step, filter, integralImage) {
  this.mWidth = width;
  this.mHeight = height;
  this.mStep = step;
  this.mFilter = filter;
  this.mLaplacian = new Array(this.mWidth);
  this.mResponses = new Array(this.mWidth);
  for (var i = 0; i < this.mWidth; i++) {
    this.mLaplacian[i] = new Array(this.mHeight);
    this.mResponses[i] = new Array(this.mHeight);
  }

  this.buildResponseLayer = function (img) {
    var b = Math.floor((this.mFilter - 1) / 2 + 1);
    var l = Math.floor(this.mFilter / 3);
    var w = this.mFilter;
    var inverse_area = 1.0 / (w * w);
    var Dxx,
      Dyy,
      Dxy;
    const ImageTransformUtils = require('./ImageTransformUtils');
    for (var r, c, ar = 0; ar < this.mHeight; ++ar) {
      for (var ac = 0; ac < this.mWidth; ++ac) {
        r = ar * this.mStep;
        c = ac * this.mStep;

        // Compute response components
        Dxx = ImageTransformUtils.BoxIntegral(img, r - l + 1, c - b, 2 * l - 1, w)
          - ImageTransformUtils.BoxIntegral(img, r - l + 1, c - Math.floor(l / 2), 2 * l - 1, l) * 3;
        Dyy = ImageTransformUtils.BoxIntegral(img, r - b, c - l + 1, w, 2 * l - 1)
          - ImageTransformUtils.BoxIntegral(img, r - Math.floor(l / 2), c - l + 1, l, 2 * l - 1) * 3;
        Dxy = +ImageTransformUtils.BoxIntegral(img, r - l, c + 1, l, l)
          + ImageTransformUtils.BoxIntegral(img, r + 1, c - l, l, l)
          - ImageTransformUtils.BoxIntegral(img, r - l, c - l, l, l)
          - ImageTransformUtils.BoxIntegral(img, r + 1, c + 1, l, l);

        // Normalise the filter responses with respect to their size
        Dxx *= inverse_area;
        Dyy *= inverse_area;
        Dxy *= inverse_area;

        // Get the determinant of hessian response & laplacian sign
        this.mResponses[ac][ar] = Dxx * Dyy - 0.81 * Dxy * Dxy;
        this.mLaplacian[ac][ar] = (Dxx + Dyy >= 0 ? 1 : 0);
      }
    }
  }

  this.getResponse = function (row, col, src) {
    if (src) {
      var scale = Math.floor(this.getWidth() / src.getWidth());
      row *= scale;
      col *= scale;
    }
    return this.mResponses[col][row];
  }

  this.getHeight = function () {
    return this.mHeight;
  }

  this.getWidth = function () {
    return this.mWidth;
  }

  this.getFilter = function () {
    return this.mFilter;
  }

  this.getStep = function () {
    return this.mStep;
  }

  this.getLaplacian = function (row, col, src) {
    if (src) {
      var scale = Math.floor(this.getWidth() / src.getWidth());
      row *= scale;
      col *= scale;
    }
    return this.mLaplacian[col][row];
  }

  this.buildResponseLayer(integralImage);
}

module.exports = ResponseLayer
